/* big_header.h */

#ifndef DODO_BIG_HEADER_H
#define DODO_BIG_HEADER_H

#include "defines.h"
#include <fstream>
#include <string>
#include <boost/multi_array.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

namespace dodomet
{
namespace mm5
{

class Big_Header;

class Big_Header_Impl
{
public:
	friend class Big_Header;
private:
	typedef boost::multi_array_ref<fortran_int, 2> bhi_array_ref;
	typedef boost::multi_array_ref<fortran_real, 2> bhr_array_ref;
	typedef boost::multi_array_ref<std::string, 2> bhc_array_ref;

	Big_Header_Impl();
	Big_Header_Impl(const Big_Header_Impl& orig);
	bool is_only();
	// read from file
	void read(std::fstream& stream);
	// queries
	fortran_int bhi(int i, int j) const {return bhi_[i][j];}
	std::string bhic(int i, int j) const {return bhic_[i][j];}
	fortran_real bhr(int i, int j) const {return bhr_[i][j];}
	std::string bhrc(int i, int j) const {return bhrc_[i][j];}

	boost::posix_time::ptime start_time(int program_index = 0) const;
	boost::posix_time::time_duration time_interval(int program_index = 0) const;
	int mm5_version(int program_index = 0) const;
	int program_version(int program_index = 0) const;
	int program_minor_version(int program_index = 0) const;
	int num_vertical_level(int program_index = 0) const;
	int data_type() const;
	
private:
	fortran_int bhi_data_[20 * 50];
	fortran_real bhr_data_[20 * 20];
	std::string bhic_data_[20 * 50];
	std::string bhrc_data_[20 * 20];

	// fortran_storage_order
	bhi_array_ref bhi_;
	// fortran_storage_order
	bhr_array_ref bhr_;
	// fortran_storage_order
	bhc_array_ref bhic_;
	// fortran_storage_order
	bhc_array_ref bhrc_;

	int use_count_;
};

/// you may need to read MM5 IO document to understand what Big_Header is.
class Big_Header
{
public:
	Big_Header();
	Big_Header(const Big_Header& orig);
	~Big_Header();

	Big_Header& operator= (const Big_Header& orig);
private:
	void on_write();
public:
	/// reading from file stream. not for user.
	void read(std::fstream& stream);

//	queries
	
	/// returns BHI(I, J).
	/**
	 * I, J starts from 1.
	 */
	fortran_int bhi(int i, int j) const {return impl_->bhi(i, j);}

	/// returns BHIC(I, J).
	/**
	 * I, J starts from 1.
	 */
	std::string bhic(int i, int j) const {return impl_->bhic(i, j);}

	/// returns BHR(I, J).
	/**
	 * I, J starts from 1.
	 */
	fortran_real bhr(int i, int j) const {return impl_->bhr(i, j);}

	/// returns BHRC(I, J).
	/**
	 * I, J starts from 1.
	 */
	std::string bhrc(int i, int j) const {return impl_->bhrc(i, j);}
	
	/// returns the start time of a program.
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	boost::posix_time::ptime start_time(int program_index = 0) const;

	/// returns time_interval of a program.	
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	boost::posix_time::time_duration time_interval(int program_index = 0) const;

	/// returns mm5_version of a program.
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	int mm5_version(int program_index = 0) const;

	/// returns program version.	
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	int program_version(int program_index = 0) const;

	/// returns program minor version.
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	int program_minor_version(int program_index = 0) const;

	/// returns vertical level number of a program.	
	/**
	 * see MM5 IO doc and defines.h for the available program_indexes(aka data types).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	int num_vertical_level(int program_index = 0) const;

	/// returns data type index of the file.
	/**
	 * see MM5 IO doc and defines.h for the available data types(aka program_indexes).
	 * 0 means selecting from the data type of the file, i.e. BHI(1, 1).
	 */
	int data_type() const;
private:
	Big_Header_Impl* impl_;
	
};


} // namespace mm5
} // namespace dodomet

#endif //DODO_BIG_HEADER_H

